#ifndef HIR_COMPILER_HPP
#define HIR_COMPILER_HPP
#pragma once

#include <exception>
#include "hir_graphbuilder.hpp"
#include "hir_instrstorage.hpp"

namespace hir
{

struct CompileDesc
{
    const unsigned char * codes_;
    size_t codeLength_;
    PyObject * consts_;
    PyObject * names_;
    PyObject * varnames_;
    PyObject * cellvars_;
    PyObject * freevars_;
    PyCodeObject * code_object_;
};


class Compiler
{
public:
    typedef Instruction * Value;
    typedef std::list<std::unique_ptr<BasicBlock> > BlockList;

    Compiler(struct CompileDesc const &);
    // actual compile command
    void compile();

    Value pop ();
    void push(Value);
    void append(std::unique_ptr<Instruction>);
private:
    void buildBasicBlock();
    void buildPreBasicBlock();
    void fixLoopJumps();
    template<class T,class Y>
    void buildPhi(T &,Y &);
    void collectBasicBlockInfo();
    void buildHir();
    BasicBlock * basicBlockAt(uint32_t bci);
    BasicBlock * findBasicBlockAt(uint32_t bci);
    BasicBlock * findBasicBlockContaining(uint32_t bci);

    inline BlockList  & basicBlocks()
    {
        return basicBlocks_;
    }

private:
    CompileDesc desc_;
    // declared in graphBuilder
    std::vector<Value> valueStack_;
    // basicBlocks ordered by bci , the last one is always exit block
    BlockList basicBlocks_;
    uint32_t currentBasicBlockId_;
    InstrStorage storage_;
};
}

#endif /* HIR_COMPILER_HPP */
